/*
 * =====================================================================================
 *
 *       Filename:  getAllTasks.c
 *
 *    Description:  
 *
 *        Version:  1.0
 *        Created:  17.4.2013 17:29:21
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  YOUR NAME (), 
 *   Organization:  
 *
 * =====================================================================================
 */

#include <linux/module.h>
#include <linux/kernel.h>

#include <linux/sched.h>

#include <linux/proc_fs.h>
#include <linux/string.h>
#include <linux/vmalloc.h>
#include <linux/uaccess.h>

// Konstanty
#define MAX_PID 32768
#define MAX_PID_LEN 6
#define STARTLEN 40
#define INCREASELEN 20
#define INPUTSIZE 16

// Globalni promenne
int *procs;
int procsCount;
int actProc;
int wasWrite;
char inputBuf[INPUTSIZE];


MODULE_LICENSE("GPL");
MODULE_AUTHOR("Radek Necas");
MODULE_DESCRIPTION("Get all proceses in task list");



int fillProcs(void)
{
    struct task_struct *task;
    int arrayLen = STARTLEN;
    int intSize = sizeof(int);
    actProc = 0;

    procsCount = 0;
    procs = (int *)kmalloc(arrayLen*intSize, GFP_KERNEL);
    if(procs == NULL) {
        printk(KERN_INFO "getAllProcs: Chyba pri alokaci pameti \n");
        return 0;
    }

    // Ziskani info o vsech procesich
    for_each_process(task) {
        if(procsCount >= arrayLen) {
            arrayLen += INCREASELEN;
            procs = (int *)krealloc(procs, arrayLen*intSize, GFP_KERNEL);
            if(procs == NULL) {
                printk(KERN_INFO "getAllProcs: Chyba pri realokaci pameti \n");
                kfree(procs);
                procsCount = 0;
                return 0;
            }
        }
        procs[procsCount] = task->pid;
        procsCount++;
    }

    wasWrite = 1;
    return procsCount;
}


static int ibpProcsRead(char *page, char **start, off_t off, int count,
        int *eof, void *data)
{
    int oldProc;
    int len;

    if(off > 0) {
        printk(KERN_INFO "getAllProcs: ibpProcsRead offset vetsi jak 0");
        return 0;
    }

    len = 0;
    if(wasWrite) {      // Pokud se jiz zadalo o zapis -> naplnily se data
        if(actProc <= procsCount) {     
            oldProc = actProc;
            actProc++;
            len=sprintf(page, "%05d\n", procs[oldProc]);
        }
        else {  // Pokud jsem prosel cele pole musi se v dalsi iter znovu zapsat
            printk(KERN_INFO "getALLProcs: Snaha cist mimo meze vsech procesu");
            wasWrite = 0;
            actProc = 0;
            procsCount = 0;
            kfree(procs);
            procs = NULL;
            *eof=1;
        }
    }

    return(len);
}

static int ibpProcsWrite(struct file *file, const char *buffer, 
        unsigned long count, void *data)
{
    int len =  fillProcs();
    actProc = 0;
    wasWrite = 1;
/*
    for(i = 0; i < procsCount; i++) {
        printk(KERN_INFO "getAllProcs: PID:  %d", procs[i]);
    }
    printk(KERN_INFO "getAllProcs: ibpProcsWrite naplnilo %d pid\n", procsCount);
*/
    return len;
}


int init_module(void)
{
    struct proc_dir_entry *ibpAllProcsFile;

    procs = NULL;
    procsCount = 0;
    actProc = 0;
    wasWrite = 0;

    ibpAllProcsFile = create_proc_entry("ibpAllProcs", 0666, NULL);
    if(ibpAllProcsFile == NULL) {
        printk(KERN_INFO "getAllProcs: Nepodarilo se vytvorit soubor v proc");

    }

    ibpAllProcsFile->data = inputBuf;
    ibpAllProcsFile->read_proc = ibpProcsRead;
    ibpAllProcsFile->write_proc = ibpProcsWrite;

    printk(KERN_INFO "getAllProcs: Modul zaveden");
    printk(KERN_INFO "");

    return 0;
}


void cleanup_module(void)
{
    remove_proc_entry("ibpAllProcs", NULL);
    if(procs != NULL)
        kfree(procs);

    printk(KERN_INFO "getAllProcs: Modul odebran");
    printk(KERN_INFO "");
}
